﻿using System;
using System.IO;
using System.Text;
using System.Configuration;
using System.Diagnostics;
using System.Threading;

namespace VPNMonitor
{
	public class Logger 
	{
		private static Logger InstanceValue;

		public static LogType logType = (LogType)Enum.Parse(typeof(LogType), ConfigurationSettings.AppSettings["Log.Type"]);
		private static String logFileName = ConfigurationSettings.AppSettings["Log.FileName"];
		private static LogLevel logLevel = (LogLevel)Enum.Parse(typeof(LogLevel), ConfigurationSettings.AppSettings["Log.Level"]);

		private Logger()
		{
		}

		public static Logger Instance
		{
			get
			{
				if (InstanceValue == null)
				{
					lock (typeof(Logger))
					{
						if (InstanceValue == null)
						{
							InstanceValue = new Logger();
						}
					}
				}

				return InstanceValue;
			}
		}

		public static void Log(String message)
		{
			Log(message, LogLevel.Info);
		}

		public static void Log(String message, LogLevel level) 
		{
			if (logLevel <= level) 
			{
				if (logType == LogType.File)
					LogToFile(message, level);
				else
					LogToEventLog(message, level);
			}
		}

		private static void LogToEventLog(string message, LogLevel level)
		{
			EventLogEntryType type = EventLogEntryType.Information;

			switch (level)
			{
				case LogLevel.Error:
					type = EventLogEntryType.Error;
					break;

				case LogLevel.Warning:
					type = EventLogEntryType.Warning;
					break;
			}

			LogToEventLog(message, type);
		}

		private static void LogToEventLog(string text)
		{
			LogToEventLog(text, EventLogEntryType.Information);
		}

		private static void LogToEventLog(string text, EventLogEntryType entryType)
		{

			string sourceName = "VPNMonitorService";

			string logName = "VPNMonitorServiceLog";

			EventLogPermission eventLogPermission = new EventLogPermission(EventLogPermissionAccess.Administer, ".");
			eventLogPermission.Assert();

			if (EventLog.LogNameFromSourceName(sourceName, ".") != logName)
			{
				EventLog.DeleteEventSource(sourceName);
			}

			if (!EventLog.SourceExists(sourceName, "."))
			{
				Thread.Sleep(5000);
				EventSourceCreationData data = new EventSourceCreationData(sourceName, logName);
				EventLog.CreateEventSource(data);
			}
			
			EventLog log = new EventLog(logName, ".", sourceName);
			log.ModifyOverflowPolicy(OverflowAction.OverwriteOlder, 3);
			log.MaximumKilobytes = 4096;
			log.WriteEntry(text, entryType);
		}

		private static void LogToFile(string message, LogLevel level)
		{
			DateTime dt = DateTime.Now;

			lock (Instance)
			{
				using (FileStream fs = new FileStream(logFileName, FileMode.Append))
				{
					StreamWriter writer = new StreamWriter(fs, Encoding.UTF8);
					writer.WriteLine(dt.ToString("yyyy.MM.dd HH.mm.ss") + " | " + level.ToString().PadLeft(8, ' ') + " | " + message);
					writer.Close();
				}
			}
		}
	}

	public enum LogLevel : int
	{
		All = 0,
		Info = 1,
		Warning = 2,
		Error = 4,
		Off = 8
	}

	public enum LogType
	{
		EventLog,
		File
	}
}
